/*
 * IMLibM.nc -- helper functions
 *
 * Copyright (C) Andrey Vihrov <andrey.vihrov@gmail.com>, 2010
 * Copyright (C) Askar Salimbaev <ghostinshell@gmail.com>, 2010
 *
 * This file is part of Intermote.
 *
 * Intermote is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Intermote is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Intermote.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <Intermote.h>

module IMLibM {

	provides {
		interface IMBlockId as BlockId;
		interface IMLocalAddress as LocalAddress;
		interface IMFirstBlock as FirstBlock;
	}

	uses {
		interface ActiveMessageAddress;

		interface Packet;
		interface AMSend as FirstBlockSend;
		interface Receive as FirstBlockReceive;
		interface IMTimeout as FirstBlockTimeout;
	}

}
implementation {

	/* BlockId interface operations */

	command am_addr_t BlockId.node (im_block_id_t id)
	{
		return (id >> 16) & 0xFFFF;
	}

	command uint16_t BlockId.number (im_block_id_t id)
	{
		return id & 0xFFFF;
	}

	command im_block_id_t BlockId.create (am_addr_t addr, uint16_t num)
	{
		return (im_block_id_t)addr << 16 | num;
	}

	command bool BlockId.isLocal (im_block_id_t id)
	{
		return call BlockId.node(id) == call LocalAddress.address();
	}


	/* LocalAddress interface operations */

	command am_addr_t LocalAddress.address (void)
	{
		return call ActiveMessageAddress.amAddress();
	}


	/* FirstBlock interface operations */

	task void firstblock_fail (void)
	{
		signal FirstBlock.getDone(FAIL, 0);
	}

	command void FirstBlock.get (am_addr_t node)
	{
		static message_t msg;

		call Packet.clear(&msg);
		call Packet.setPayloadLength(&msg, 0);
		if (call FirstBlockSend.send(node, &msg, 0) != SUCCESS)
			post firstblock_fail();
		else
			call FirstBlockTimeout.start();
	}

	event void FirstBlockSend.sendDone (message_t *msg, error_t err)
	{
		if (err != SUCCESS)
		{
			call FirstBlockTimeout.stop();
			signal FirstBlock.getDone(err, 0);
		}
	}

	event void FirstBlockTimeout.timeout (void)
	{
		//TODO Query other nodes

		signal FirstBlock.getDone(FAIL, 0);
	}

	event message_t *FirstBlockReceive.receive (message_t *msg, void *payload, uint8_t len)
	{
		if (len == sizeof(nx_uint32_t))
		{
			call FirstBlockTimeout.stop();
			signal FirstBlock.getDone(SUCCESS, *(const nx_uint32_t *)payload);
		}

		return msg;
	}


	/* ActiveMessageAddress events */

	async event void ActiveMessageAddress.changed (void)
	{

	}

}
